package com.sinodata.bsm.cicp.collector.sqlserver;

import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.AbstractJDBCCollector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.cicp.util.DBConnectionUtil;
import com.sinodata.bsm.common.constants.SeparatorConstants;
import com.sinodata.bsm.common.vo.ResPropertyValue;

public class Log extends AbstractJDBCCollector {
    private static final Logger logger = Logger.getLogger(Log.class);

    //    private static final int DEADLOCK_WAIT_TIME = 60;

    @Override
    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        List<ResPropertyValue> values = new ArrayList<ResPropertyValue>();
        try {
            String[] propMetas = getPropMeta();
            String serverName = this.getParamMap().get("服务器名");

            String sql = "sp_getsvrinfo";
            String[] rs = this.getStrings(serverName, sql, ip);

            ResPropertyValue propertyValueX = new ResPropertyValue();
            ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];
            for (int i = 0; i < propMetas.length; i++) {
                propValues[i] = ResPropertyValue.createPropValue(rs[i], propMetas[i]);
            }

            propertyValueX.setValues(propValues);
            values.add(propertyValueX);
        } catch (Exception e) {
            logger.error("failed to collect sqlserver log", e);
            throw new CollectorException(e);
        }
        return values;
    }

    private String[] getStrings(String serverName, String sql, String ip) throws CollectorException {
        String[] propValArr = new String[3];
        CallableStatement statement = null;
        Statement stmt = null;
        ResultSet rst = null;
        CallableStatement cstmtLog = null;
        ResultSet rstLog = null;
        Connection conn = null;
        try {
            conn = DBConnectionUtil.getInstance().getConnection("sqlserver", ip, serverName);
            if (conn != null) {
                statement = conn.prepareCall(sql);
                statement.setQueryTimeout(10);
                rst = statement.executeQuery();
                String version = "2000";
                while (rst.next()) {
                    String name = rst.getString(2);
                    if (name.equals("FileVersion")) {
                        version = rst.getString(4);
                        break;
                    }
                }

                // Get all of log id
                sql = "{call master.dbo.xp_enumerrorlogs}";
                statement = conn.prepareCall(sql);
                statement.setQueryTimeout(10);
                rst = statement.executeQuery();
                int count = 0;
                if (rst == null) {
                    return null;
                }
                while (rst.next()) {
                    if (count > 5)
                        break;
                    String logID = rst.getString(1).trim();
                    count++;
                    String logDate = rst.getString(2).trim();
                    logDate = formatDate(logDate.substring(0, 10), "yyyy/MM/dd") + logDate.substring(10, 17);
                    String logSize = rst.getString(3).trim();

                    // ////////////////////错误日志详细信息////////////////////////
                    StringBuffer errLog = new StringBuffer();
                    // 日期,源,消息
                    errLog.append("日期").append(SeparatorConstants.COL_SEPARATOR);
                    errLog.append("源").append(SeparatorConstants.COL_SEPARATOR);
                    errLog.append("消息").append(SeparatorConstants.COL_SEPARATOR);
                    errLog.append(SeparatorConstants.LIN_SEPARATOR);

                    String sqlLog = null;
                    if (logID.equals("0")) {
                        sqlLog = "{call master.dbo.xp_readerrorlog}";
                        // cstmtLog = conn.prepareCall(sqlLog,
                        // ResultSet.TYPE_SCROLL_SENSITIVE,
                        // ResultSet.CONCUR_READ_ONLY);
                        cstmtLog = conn.prepareCall(sqlLog);
                    } else {
                        sqlLog = "{call master.dbo.xp_readerrorlog(?)}";
                        // cstmtLog = conn.prepareCall(sqlLog,
                        // ResultSet.TYPE_SCROLL_SENSITIVE,
                        // ResultSet.CONCUR_READ_ONLY);
                        cstmtLog = conn.prepareCall(sqlLog);
                        cstmtLog.setInt(1, Integer.parseInt(logID));
                    }
                    rstLog = cstmtLog.executeQuery();
                    String errLogStr = null;
                    if (version.contains("2000")) {
                        errLogStr = getErrorLog2000(rstLog, errLog);
                    } else if (version.contains("2005")) {
                        errLogStr = getErrorLog2005(rstLog, errLog);
                    }

                    propValArr[0] = logDate + "";
                    propValArr[1] = logSize + "";
                    propValArr[2] = errLogStr;
                }
                return propValArr;
            } else {
                return null;
            }
        } catch (SQLException ex) {
            logger.error("when query SQL Server database " + serverName, ex);

            throw new CollectorException(ex);

        } catch (IOException ioe) {
            logger.error("when query SQL Server " + serverName, ioe);
            throw new CollectorException(ioe);
        } finally {
            closeResultSet(rst);
            closeResultSet(rstLog);
            closeStatement(cstmtLog);
            closeStatement(stmt);
            closeStatement(statement);
            DBConnectionUtil.getInstance().returnConnection(conn);
        }
    }

    @Override
    public String[] getParamMeta() {
        return new String[] { "服务器名" };
    }

    @Override
    public String[] getPropMeta() {
        return new String[] { "日期", "文件大小", "最新20条日志" };
    }

    private static void closeResultSet(ResultSet rst) throws CollectorException {
        try {
            if (rst != null)
                rst.close();
        } catch (SQLException ex) {
            logger.error("failed to close result set", ex);
            throw new CollectorException(ex);
        }
    }

    private static void closeStatement(Statement sta) throws CollectorException {
        try {
            if (sta != null)
                sta.close();
        } catch (SQLException ex) {
            logger.error("failed to close statement", ex);
            throw new CollectorException(ex);
        }
    }

    private String formatDate(String strdate, String format) {
        StringTokenizer st = new StringTokenizer(strdate, "/");
        int i = 0;
        int[] dateItem = new int[3];
        while (st.hasMoreElements()) {
            if (i == 3)
                break;
            dateItem[i] = Integer.parseInt(st.nextElement().toString());
            i++;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.set(dateItem[2], dateItem[0] - 1, dateItem[1]);
        SimpleDateFormat fmt = new SimpleDateFormat(format);
        return fmt.format(calendar.getTime());
    }

    private String getErrorLog2000(ResultSet rstLog, StringBuffer errLog) throws CollectorException {
        List<String> errorLogList = new ArrayList<String>();
        if (rstLog == null) {
            return errLog.toString();
        }
        try {
            // rstLog.last();
            // while (rstLog.previous()) {
            while (rstLog.next()) {
                String errorLog = rstLog.getString(1);
                String logtime = errorLog.substring(0, 22);
                String source = errorLog.substring(23, 32);
                String message = errorLog.substring(33, errorLog.length());
                StringBuffer tmpBuffer = new StringBuffer();
                tmpBuffer.append(logtime);
                tmpBuffer.append(SeparatorConstants.COL_SEPARATOR);
                tmpBuffer.append(source);
                tmpBuffer.append(SeparatorConstants.COL_SEPARATOR);
                tmpBuffer.append(message);
                tmpBuffer.append(SeparatorConstants.COL_SEPARATOR);
                tmpBuffer.append(SeparatorConstants.LIN_SEPARATOR);
                errorLogList.add(tmpBuffer.toString()); //每个日志文件中的记录不多，应该不会溢出。
            }
        } catch (SQLException e) {
            logger.error("failed to get error log2000", e);
            throw new CollectorException(e);
        }

        //bottom 20
        int size = errorLogList.size();
        List bottomLogList = null;
        if (size > 20)
            bottomLogList = errorLogList.subList(size - 20, size);
        else
            bottomLogList = errorLogList;

        Iterator it = bottomLogList.iterator();
        while (it.hasNext()) {
            String errorLogRec = it.next().toString();
            errLog.append(errorLogRec);
        }

        return errLog.toString();

    }

    private String getErrorLog2005(ResultSet rstLog, StringBuffer errLog) throws CollectorException {
        List<String> errorLogList = new ArrayList<String>();
        if (rstLog == null) {
            return errLog.toString();
        }
        try {
            // rstLog.last();
            // while (rstLog.previous()) {
            while (rstLog.next()) {
                String logtime = rstLog.getString(1);
                String source = rstLog.getString(2);
                String message = rstLog.getString(3);
                StringBuffer tmpBuffer = new StringBuffer();
                tmpBuffer.append(logtime);
                tmpBuffer.append(SeparatorConstants.COL_SEPARATOR);
                tmpBuffer.append(source);
                tmpBuffer.append(SeparatorConstants.COL_SEPARATOR);
                tmpBuffer.append(message);
                tmpBuffer.append(SeparatorConstants.COL_SEPARATOR);
                tmpBuffer.append(SeparatorConstants.LIN_SEPARATOR);
                errorLogList.add(tmpBuffer.toString()); //每个日志文件中的记录不多，应该不会溢出。
            }
        } catch (SQLException e) {
            logger.error("failed to get error log2005", e);
            throw new CollectorException(e);
        }

        //bottom 20
        int size = errorLogList.size();
        List bottomLogList = null;
        if (size > 20)
            bottomLogList = errorLogList.subList(size - 20, size);
        else
            bottomLogList = errorLogList;

        Iterator it = bottomLogList.iterator();
        while (it.hasNext()) {
            String errorLogRec = it.next().toString();
            errLog.append(errorLogRec);
        }

        return errLog.toString();
    }

}
